import pdb
import random
import time
import uuid
from datetime import timedelta, datetime

from sqlalchemy import func

from app.models import db
from app.models.ticket_lib import Ticket
from app.models.train_station_lib import TrainStation


# 定义 Order 类，继承自 db.Model，用于表示数据库中的订单表
class Order(db.Model):
    # 指定数据库表名为 'order'
    __tablename__ = 'order'

    # 定义主键列，类型为整数，自动递增
    id = db.Column(db.Integer, primary_key=True)
    # 定义订单编号列，类型为字符串，最大长度 120，唯一且不能为空
    order_no = db.Column(db.String(120), unique=True, nullable=False)
    # 定义订单价格列，类型为数值，总位数 8，小数位数 2
    price = db.Column(db.Numeric(8, 2))
    # 定义支付时间列，类型为日期时间
    payment_time = db.Column(db.DateTime)
    # 定义订单状态列，类型为整数，默认值为 0
    state = db.Column(db.Integer, default=0)
    # 定义乘客 ID 列，类型为整数，关联到 'passenger' 表的 'id' 列，不能为空，并创建索引
    passenger_id = db.Column(db.Integer, db.ForeignKey('passenger.id'), nullable=False, index=True)
    # 定义创建时间列，类型为日期时间，默认值为当前时间
    created_at = db.Column(db.DateTime, default=func.now())
    # 定义更新时间列，类型为日期时间，默认值为当前时间
    updated_at = db.Column(db.DateTime, default=func.now())

    # 定义与 Passenger 模型的关联关系，通过 backref 可以从 Passenger 模型访问相关的订单
    passenger = db.relationship('Passenger', backref=db.backref('orders'))

    def __repr__(self):
        """
        返回订单对象的字符串表示形式，方便调试和日志记录
        :return: 包含订单 ID 的字符串
        """
        return f'<Order {self.id}>'

    @classmethod
    def setOrderState(cls, order_no, passenger_id, **kwargs):
        """
        根据订单编号和乘客 ID 更新订单状态及其他属性，并在状态更新为 1 时更新相关车票状态

        :param order_no: 订单编号
        :param passenger_id: 乘客 ID
        :param kwargs: 要更新的订单属性键值对
        :return: 更新后的订单对象，如果未找到订单则返回 None
        """
        # 根据订单编号和乘客 ID 查询订单
        order = cls.query.filter_by(order_no=order_no, passenger_id=passenger_id).first()
        if order:
            # 遍历传入的关键字参数，更新订单的属性
            for key, value in kwargs.items():
                # 使用 setattr 函数设置订单对象的属性
                setattr(order, key, value)
                # 如果更新的属性是 'state' 且值为 1
                if key == 'state' and value == 1:
                    # 遍历订单中的所有车票
                    for ticket in order.tickets:
                        # 调用 Ticket 类的 updateState 方法更新车票状态为 1
                        Ticket.updateState(ticket)  # Update state to 1
            # 提交更改到数据库
            db.session.commit()
            # 返回更新后的订单对象
            return order
        else:
            # 处理订单未找到的情况，返回 None
            return None


def generate_unique_id(length=4):
    # 获取当前的秒级时间戳，用于确保生成的 ID 在时间维度上具有唯一性
    timestamp_seconds = int(time.time())

    # 生成 4 位随机数，增加 ID 的随机性
    random_number = random.randint(0, 10 ** length - 1)

    # 确保随机数是 4 位数字，如果不足 4 位，在前面补 0
    random_number_str = str(random_number).zfill(length)

    # 生成唯一标识符，将时间戳和 4 位随机数拼接在一起
    unique_id = f"{timestamp_seconds}{random_number_str}"
    return unique_id


def generateOrder(params, passenger_id):
    """
    根据传入的参数和乘客 ID 生成一个新的订单对象

    :param params: 包含车票信息的字典
    :param passenger_id: 乘客的 ID
    :return: 生成的订单对象
    """
    # 创建一个新的 Order 对象
    order = Order(
        # 调用 generate_unique_id 函数生成 5 位长度的唯一订单编号
        order_no=generate_unique_id(5),
        # 关联乘客 ID
        passenger_id=passenger_id
    )

    # 遍历传入参数中的车票信息
    for e in params['tickets']:
        # 创建 Ticket 对象，调用 Ticket 类的 generateTicket 方法
        ticket = Ticket.generateTicket(e, passenger_id)
        # 从数据库中查询起始站信息，根据车次和起始站名称
        from_station = TrainStation.query.filter_by(train_no=ticket.train_no, station_name=ticket.from_station).one()
        # 从数据库中查询终点站信息，根据车次和终点站名称
        to_station = TrainStation.query.filter_by(train_no=ticket.train_no, station_name=ticket.to_station).one()
        # 查询车次中从起始站到终点站的所有站点信息
        train_stations = TrainStation.query.filter(
            TrainStation.train_no == ticket.train_no,
            TrainStation.index.between(from_station.index, to_station.index)
        ).all()
        # 计算车票价格，将区间内所有站点的价格相加
        ticket.price = sum(e.price for e in train_stations)
        # 计算当前车次和日期下已售出车票的数量
        seat_count = db.session.query(func.count(Ticket.id)).filter_by(
            train_no=ticket.train_no,
            date=ticket.date
        ).scalar()
        # 为车票分配座位号，座位号为已售车票数量加 1
        ticket.seat_no = seat_count + 1

        # 计算车票日期与起始站出发日期的天数差
        interval_days = (
                datetime.strptime(ticket.date, "%Y/%m/%d") - datetime.combine(from_station.departure_time.date(),
                                                                              datetime.min.time())).days
        # 计算车票的出发时间，考虑日期差
        ticket.departure_time = from_station.departure_time + timedelta(days=interval_days)
        # 计算车票的到达时间，考虑日期差
        ticket.arrival_time = to_station.arrival_time + timedelta(days=interval_days)

        # 将生成的车票添加到订单的车票列表中
        order.tickets.append(ticket)

    # 计算订单总价，将订单中所有车票的价格相加
    order.price = sum(ticket.price for ticket in order.tickets)

    return order
